/*
XPTracker - Alternative Agile Tracking Tool
Copyright (C) 2006-2009  Stephen Starkey

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
*/
package org.xptracker.services;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xptracker.domain.Domain;
import org.xptracker.domain.EmailConfiguration;
import org.xptracker.domain.User;

import javax.mail.Address;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;

@Singleton
public class EmailService {
  private static Log logger = LogFactory.getLog(EmailService.class);

  private Domain domain;

  @Inject
  public void setDomain(Domain d) {
    this.domain = d;
  }

  private EmailConfiguration getConfiguration() {
    return domain.loadEmailConfiguration();
  }

  public void sendEmail(User from, User to, String subject, String body) {
    Set<User> recipients = new HashSet<User>();
    recipients.add(to);
    sendEmail(from, recipients, subject, body);
  }

  public void sendEmail(User sender, Set<User> recipients, String subject, String messageStr) throws EmailServiceException {
    EmailConfiguration configuration = getConfiguration();
    if (configuration.isEnabled()) {
      if (!recipients.isEmpty()) {
        java.security.Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
        Properties props = new Properties();
        props.put("mail.smtp.host", configuration.getSmtpHost());
        props.put("mail.smtp.auth", "" + configuration.useAuthentication());
        if (configuration.useAuthentication()) {
          props.put("mail.smtp.starttls.enable","true");
        }

        Session session = Session.getInstance(props, null);
        try {
          MimeMessage message = new MimeMessage(session);
          message.setFrom(createAddress(sender.getEmail()));
          addRecipients(recipients, message);
          final Address[] addresses = message.getAllRecipients();
          if(addresses == null) {
            return;
          }
          message.setSubject(subject);
          message.setText(messageStr);
          Transport t = session.getTransport("smtp");
          try {
            if (configuration.useAuthentication()) {
              t.connect(configuration.getUsername(), configuration.getPassword());
            } else {
              t.connect();
            }
            t.sendMessage(message, message.getAllRecipients());
          } finally {
            t.close();
          }
        } catch (MessagingException e) {
          logger.error(e);
          throw new EmailServiceException("Error occurred sending email message: " + e.getMessage(), e);
        }
      } else {
        logger.warn("Sending message aborted.  There are no recipients");
      }
    } else {
      logger.info("Email sending is not enabled.");
    }
  }

  private void addRecipients(Set<User> recipients, MimeMessage message) throws MessagingException {
    for (User recipient : recipients) {
      if (recipient != null) {
        if (recipient.isEnabled()) {
          final InternetAddress address = createAddress(recipient.getEmail());
          if (address != null) {
            message.addRecipient(MimeMessage.RecipientType.TO, address);
            logger.debug("* recipient: " + address);
          } else {
            logger.warn("Could not add recipient address for " + recipient.getUsername() +
                " with email address of " + recipient.getEmail());
          }
        } else {
          logger.info("Recipient disabled: " + recipient);
        }
      } else {
        logger.warn("Recipient was null!");
      }
    }
  }

  private InternetAddress createAddress(String email) throws RuntimeException {
    if (StringUtils.isNotBlank(email)) {
      try {
        return new InternetAddress(email);
      } catch (AddressException e) {
        logger.error("Error parsing email address ", e);
      }
    }
    return null;
  }
}
